package demo.impl.icmp;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.pcap4j.core.PacketListener;
import org.pcap4j.packet.IcmpV4EchoReplyPacket;
import org.pcap4j.packet.Packet;
import org.pcap4j.packet.namednumber.IcmpV4Type;
import org.slf4j.LoggerFactory;

import demo.api.IcmpEchoSession;
import demo.impl.AbstractProtocolService;
import demo.util.AssertUtils;

/**
 * 负责响应所有Echo Packet，管理和分发echo session的packet
 * 
 * @author caohj
 * @date 2017年8月5日
 */
public class IcmpEchoListener extends AbstractProtocolService<IcmpV4EchoReplyPacket> implements PacketListener {
	/** 所有的Echo 会话 */
	private Map<Short/* identifier */, IcmpEchoSession> listeners = new ConcurrentHashMap<Short, IcmpEchoSession>();

	public IcmpEchoListener() {
		super(null);
	}

	/**
	 * 注册一个Echo Session
	 * 
	 * @param identifier
	 * @param session
	 * @return 前一个失效的session，如果有
	 */
	public IcmpEchoSession registerEchoSession(short identifier, IcmpEchoSession session) {
		AssertUtils.notNull(session, "参数session不能为空！");

		LoggerFactory.getLogger(getClass()).info("注册EchoSession：session identifier=" + identifier);
		IcmpEchoSession last = listeners.put(identifier, session);
		if (last != null) {
			LoggerFactory.getLogger(getClass()).info("前一个EchoSession已失效：session identifier=" + identifier);
		}

		return last;
	}

	/**
	 * 注销Echo Session
	 * 
	 * @param identifier
	 * @return
	 */
	public IcmpEchoSession unregisterEchoSession(short identifier) {
		IcmpEchoSession last = listeners.remove(identifier);
		if (last != null) {
			LoggerFactory.getLogger(getClass()).info("注销EchoSession：session identifier=" + identifier);
		}
		return last;
	}

	@Override
	public void gotPacket(Packet packet) {
		if (packet.contains(IcmpV4EchoReplyPacket.class)) {
			short identifier = getHighLevelProtocolType(packet.get(IcmpV4EchoReplyPacket.class)).shortValue();
			PacketListener listener = listeners.get(identifier);
			if (listener != null) {
				listener.gotPacket(packet);
			}
		}
	}

	@Override
	protected Number getProtocolType() {
		return IcmpV4Type.ECHO_REPLY.value();
	}

	@Override
	protected Number getHighLevelProtocolType(IcmpV4EchoReplyPacket packet) {
		return packet.getHeader().getIdentifier();
	}

}
